#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>

#include <sys/epoll.h>

#define SERVPORT 3333 //定义端口号
#define BACKLOG 10 //请求队列中允许的最大请求数
#define MAXDATASIZE 50 //数据长度
#define MAXEVENTS 128

int main() {
    struct sockaddr_in server_sockaddr, client_sockaddr;
    int sin_size, recvbytes;
    int sockfd, client_fd; 
    char buf[MAXDATASIZE];
	
	int n, i; 
	int efd; 
	struct epoll_event event; 
	struct epoll_event *events;
		
    if((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("创建 server socket 失败");
        exit(1);
    }

    printf("Socket success!,sockfd=%d\n", sockfd);

    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(SERVPORT);
    server_sockaddr.sin_addr.s_addr = INADDR_ANY;
	
    if((bind(sockfd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr))) == -1) {
        perror("bind");
        exit(-1);
    }

    printf("bind success!\n");
	
    if(listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    printf("listening ... \n");
	
	efd = epoll_create1(0);
    if (efd == -1) {
        perror("epoll create failed");
    }
	
	event.data.fd = sockfd;
    event.events = EPOLLIN | EPOLLET;
    if (epoll_ctl(efd, EPOLL_CTL_ADD, sockfd, &event) == -1) {
        perror("epoll_ctl add listen fd failed");
    }

    events = calloc(MAXEVENTS, sizeof(event));
	
	for (;;) {
		n = epoll_wait(efd, events, MAXEVENTS, -1);
		printf("epoll_wait wakeup\n");
		for (i = 0; i < n; i++) {
			if ((events[i].events & EPOLLERR) || 	
				(events[i].events & EPOLLHUP) || 
				(!(events[i].events & EPOLLIN))) { 
				fprintf(stderr, "epoll error\n"); 
				close(events[i].data.fd); 
				continue;	
			} else if (sockfd == events[i].data.fd) {
    			if((client_fd = accept(sockfd, (struct sockaddr *) &client_sockaddr, &sin_size)) == -1) {
        			perror("accept");
        			exit(1);
    			}
				event.data.fd = client_fd; 
				event.events = EPOLLIN | EPOLLET; //edge-triggered 
				if (epoll_ctl(efd, EPOLL_CTL_ADD, client_fd, &event) == -1) { 
					perror("epoll_ctl add connection fd failed"); 
				}	
				continue;
			} else {
				int socket_fd = events[i].data.fd;
				printf("get event on socket fd == %d \n", socket_fd);
    			if((recvbytes = read(socket_fd, buf, MAXDATASIZE)) == -1) {
        			perror("recv");
        			exit(1);
    			}
			
				// 收到数据大小为 0，说明收到的是 FIN 终止连接请求
				if (recvbytes == 0) {
					close(socket_fd);
					continue;
				}		
	
    			printf("received a connection : %s\n", buf);
				// 清空 buf
				memset(buf, 0x00, sizeof(buf));

				// 模拟处理延迟，睡 2 秒
				sleep(2);
		
				write(socket_fd, "hello server", 13);

				// 模拟处理延迟，睡 2 秒
				sleep(2);
				// write again
				write(socket_fd, "hello server2", 14);
				
			}
		}
	}
	free(events);
    close(sockfd);

}
